/*
 * Copyright (c) 2022, IMMORTA Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * - Redistributions of source code must retain the above copyright notice, this list
 *   of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright notice, this
 *   list of conditions and the following disclaimer in the documentation and/or
 *   other materials provided with the distribution.
 *
 * - Neither the name of IMMORTA Inc. nor the names of its
 *   contributors may be used to endorse or promote products derived from this
 *   software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/*!
 * @file pmc_driver.c
 * @brief This file defines pmc driver functions
 */

/*******Includes***************************************************************/
#include <stddef.h>
#include "gpio_reg_access.h"

/*******Definitions************************************************************/

/*******Variables**************************************************************/

/*******Prototypes*************************************************************/

/*******Private Functions******************************************************/

/*******Code*******************************************************************/

/*******************************************************************************
 *** Function Name : GPIO_Init
 *** Description   : Initializes the pins with the options provided in the structure
 ******************************************************************************/
void GPIO_Init(uint8_t pinCount,
               const gpio_pin_config_t* gpioConfig)
{
    ASSERT_PARAM(gpioConfig != NULL);

    for (uint32_t i = 0U; i < pinCount; i++) {
        GPIO_REG_Init(&gpioConfig[i]);
    }
}

/*******************************************************************************
 *** Function Name : GPIO_SetPinMode
 *** Description   : Configure the mode for the given pin with the given mode
 ******************************************************************************/
void GPIO_SetPinMode(GPIO_Type* regBase,
                     uint32_t pinNum,
                     gpio_pin_mode_t pinMode)
{
    ASSERT_PARAM(pinNum < PORT_PIN_COUNT);

    GPIO_REG_SetPinMode(regBase, pinNum, pinMode);
}

/*******************************************************************************
 *** Function Name : GPIO_GetPinMode
 *** Description   : Get the pin mode configuration for the given pin
 ******************************************************************************/
gpio_pin_mode_t GPIO_GetPinMode(const GPIO_Type* regBase,
                                uint32_t pinNum)
{
    ASSERT_PARAM(pinNum < PORT_PIN_COUNT);

    return (GPIO_REG_GetPinMode(regBase, pinNum));
}

/*******************************************************************************
 *** Function Name : GPIO_SetPinPull
 *** Description   : Configures the internal resistor for the given pin
 ******************************************************************************/
void GPIO_SetPinPull(GPIO_Type* regBase,
                     uint32_t pinNum,
                     gpio_pin_pull_t pullConfig)
{
    ASSERT_PARAM(pinNum < PORT_PIN_COUNT);

    GPIO_REG_SetPinPull(regBase, pinNum, pullConfig);
}

/*******************************************************************************
 *** Function Name : GPIO_SetPinSlewRate
 *** Description   : Configures the slew rate for the given pin
 ******************************************************************************/
void GPIO_SetPinSlewRate(GPIO_Type* regBase,
                         uint32_t pinNum,
                         gpio_pin_slew_rate_t slewRate)
{
    GPIO_REG_SetPinSlewRate(regBase, pinNum, slewRate);
}

/*******************************************************************************
 *** Function Name : GPIO_SetPinLock
 *** Description   : Configures the pin lock for the given pin
 ******************************************************************************/
void GPIO_SetPinLock(GPIO_Type* regBase,
                     uint32_t pinNum,
                     bool pinLock)
{
    ASSERT_PARAM(pinNum < PORT_PIN_COUNT);

    GPIO_REG_SetPinLock(regBase, pinNum, pinLock);
}

/*******************************************************************************
 *** Function Name : GPIO_SetPinFunc
 *** Description   : Configures the pin mux function for the given pin
 ******************************************************************************/
void GPIO_SetPinFunc(GPIO_Type* regBase,
                     uint32_t pinNum,
                     gpio_pin_mux_t pinmux)
{
    ASSERT_PARAM(pinNum < PORT_PIN_COUNT);

    GPIO_REG_SetPinFunc(regBase, pinNum, pinmux);
}

/*******************************************************************************
 *** Function Name : GPIO_SetPinDriveStrength
 *** Description   : Configures the pin drive strength for the given pin
 ******************************************************************************/
void GPIO_SetPinDriveStrength(GPIO_Type* regBase,
                              uint32_t pinNum,
                              gpio_pin_drv_t driveStrength)
{
    ASSERT_PARAM(pinNum < PORT_PIN_COUNT);

    GPIO_REG_SetPinDriveStrength(regBase, pinNum, driveStrength);
}

/*******************************************************************************
 *** Function Name : GPIO_SetPinInt
 *** Description   : Configures the GPIO pin external interrupt
 ******************************************************************************/
void GPIO_SetPinInt(GPIO_Type* regBase,
                    uint32_t pinNum,
                    gpio_pin_int_t intConfig)
{
    ASSERT_PARAM(pinNum < PORT_PIN_COUNT);

    GPIO_REG_SetPinInt(regBase, pinNum, intConfig);
}

/*******************************************************************************
 *** Function Name : GPIO_GetPinInt
 *** Description   : Gets the current GPIO pin external interrupt configuration
 ******************************************************************************/
gpio_pin_int_t GPIO_GetPinInt(const GPIO_Type* regBase,
                              uint32_t pinNum)
{
    ASSERT_PARAM(pinNum < PORT_PIN_COUNT);

    return (GPIO_REG_GetPinInt(regBase, pinNum));
}

/*******************************************************************************
 *** Function Name : GPIO_GetPinInt
 *** Description   : Gets the pin external interrupt flag
 ******************************************************************************/
bool GPIO_GetPinIntFlag(const GPIO_Type* regBase,
                        uint32_t pinNum)
{
    ASSERT_PARAM(pinNum < PORT_PIN_COUNT);

    return (GPIO_REG_GetPinIntFlag(regBase, pinNum));
}

/*******************************************************************************
 *** Function Name : GPIO_ClearPinIntFlag
 *** Description   : Clears the individual pin external interrupt flag
 ******************************************************************************/
void GPIO_ClearPinIntFlag(GPIO_Type* regBase,
                          uint32_t pinNum)
{
    ASSERT_PARAM(pinNum < PORT_PIN_COUNT);

    GPIO_REG_ClearPinIntFlag(regBase, pinNum);
}

/*******************************************************************************
 *** Function Name : GPIO_GetPortIntFlag
 *** Description   : Reads the entire port external interrupt flag
 ******************************************************************************/
uint32_t GPIO_GetPortIntFlag(const GPIO_Type* regBase)
{
    return (GPIO_REG_GetPortIntFlag(regBase));
}

/*******************************************************************************
 *** Function Name : GPIO_ClearPortIntFlag
 *** Description   : Clears the entire port external interrupt flag
 ******************************************************************************/
void GPIO_ClearPortIntFlag(GPIO_Type* regBase)
{
    GPIO_REG_ClearPortIntFlag(regBase);
}

/*******************************************************************************
 *** Function Name : GPIO_SetDigitalFilterWidth
 *** Description   : Configures digital filter for port with given configuration
 ******************************************************************************/
#if (CONFIG_GPIO_SUPPORT_INDEPENDENT_DFL == 1U)
void GPIO_SetDigitalFilterRUNWidth(GPIO_Type* regBase,
                                   uint8_t width)
{
    ASSERT_PARAM(width <= (GPIO_DFL_RMDFL_Msk >> GPIO_DFL_RMDFL_Pos));

    GPIO_REG_SetDigitFltrRUNWidth(regBase, width);
}
#else
void GPIO_SetDigitalFilterWidth(GPIO_Type* regBase,
                                uint8_t width)
{
    ASSERT_PARAM(width <= GPIO_DFL_DFL_Msk);

    GPIO_REG_SetDigitFltrWidth(regBase, width);
}
#endif

/*******************************************************************************
 *** Function Name : GPIO_EnablePinDigitalFilterRUN
 *** Description   : Enables digital filter for the given digital pin in run mode
 ******************************************************************************/
void GPIO_EnablePinDigitalFilterRUN(GPIO_Type* regBase,
                                    uint32_t pinNum)
{
    ASSERT_PARAM(pinNum < PORT_PIN_COUNT);

    GPIO_REG_EnablePinDigitFltrRUN(regBase, pinNum);
}

/*******************************************************************************
 *** Function Name : GPIO_DisablePinDigitalFilterRUN
 *** Description   : Disables digital filter for the given digital pin in run mode
 ******************************************************************************/
void GPIO_DisablePinDigitalFilterRUN(GPIO_Type* regBase,
                                     uint32_t pinNum)
{
    ASSERT_PARAM(pinNum < PORT_PIN_COUNT);

    GPIO_REG_DisablePinDigitFltrRUN(regBase, pinNum);
}

/*******************************************************************************
 *** Function Name : GPIO_EnablePinDigitalFilterLP
 *** Description   : Enables digital filter for the given pin in lowpower mode
 ******************************************************************************/
#if (CONFIG_GPIO_SUPPORT_INDEPENDENT_DFL == 1U)
void GPIO_EnablePinDigitalFilterLP(GPIO_Type* regBase,
                                   uint32_t pinNum,
                                   uint8_t width)
{
    ASSERT_PARAM(pinNum < PORT_PIN_COUNT);
    ASSERT_PARAM(width <= (GPIO_DFL_LPDFL_Msk >> GPIO_DFL_LPDFL_Pos));

    GPIO_REG_EnablePinDigitFltrLP(regBase, pinNum);
    GPIO_REG_SetDigitFltrLPWidth(regBase, width);
}
#else
void GPIO_EnablePinDigitalFilterLP(GPIO_Type* regBase,
                                   uint32_t pinNum)
{
    ASSERT_PARAM(pinNum < PORT_PIN_COUNT);

    GPIO_REG_EnablePinDigitFltrLP(regBase, pinNum);
}
#endif

/*******************************************************************************
 *** Function Name : GPIO_DisablePinDigitalFilterLP
 *** Description   : Disables digital filter for the given port in lowpower mode
 ******************************************************************************/
void GPIO_DisablePinDigitalFilterLP(GPIO_Type* regBase)
{
    GPIO_REG_DisablePinDigitFltrLP(regBase);
}

/*******************************************************************************
 *** Function Name : GPIO_WritePin
 *** Description   : Writes a pin for the given pin with a given value
 ******************************************************************************/
void GPIO_WritePin(GPIO_Type* regBase,
                   uint32_t pinNum,
                   gpio_pin_level_t pinLevel)
{
    ASSERT_PARAM(pinNum < PORT_PIN_COUNT);

    uint32_t pinsValue = GPIO_REG_GetPinsOutput(regBase);
    if (pinLevel == GPIO_PIN_LEVEL_HIGH) {
        pinsValue |= (1U << pinNum);
    } else {
        pinsValue &= ~(1U << pinNum);
    }

    GPIO_REG_WritePins(regBase, pinsValue);
}

/*******************************************************************************
 *** Function Name : GPIO_WritePins
 *** Description   : Writes all pins configured as output
 ******************************************************************************/
void GPIO_WritePins(GPIO_Type* regBase,
                    uint32_t pinMsk)
{
    GPIO_REG_WritePins(regBase, pinMsk);
}

/*******************************************************************************
 *** Function Name : GPIO_GetPinsOutput
 *** Description   : Gets the current output for the given port
 ******************************************************************************/
uint32_t GPIO_GetPinsOutput(const GPIO_Type* regBase)
{
    return (GPIO_REG_GetPinsOutput(regBase));
}

/*******************************************************************************
 *** Function Name : GPIO_SetPins
 *** Description   : Writes pins to logic HIGH
 ******************************************************************************/
void GPIO_SetPins(GPIO_Type* regBase,
                  uint32_t pinMsk)
{
    GPIO_REG_SetPins(regBase, pinMsk);
}

/*******************************************************************************
 *** Function Name : GPIO_ResetPins
 *** Description   : Writes pins to logic LOW
 ******************************************************************************/
void GPIO_ResetPins(GPIO_Type* regBase,
                    uint32_t pinMsk)
{
    GPIO_REG_ResetPins(regBase, pinMsk);
}

/*******************************************************************************
 *** Function Name : GPIO_TogglePins
 *** Description   : Toggles pins output
 ******************************************************************************/
void GPIO_TogglePins(GPIO_Type* regBase,
                     uint32_t pinMsk)
{
    GPIO_REG_TogglePins(regBase, pinMsk);
}

/*******************************************************************************
 *** Function Name : GPIO_ReadPin
 *** Description   : Reads input pin for the given pin
 ******************************************************************************/
gpio_pin_level_t GPIO_ReadPin(const GPIO_Type* regBase,
                              uint32_t pinNum)
{
    ASSERT_PARAM(pinNum < PORT_PIN_COUNT);

    uint32_t pinsValue = GPIO_REG_ReadPins(regBase);
    pinsValue = ((pinsValue >> pinNum) & 0x01U);

    return (gpio_pin_level_t)pinsValue;
}

/*******************************************************************************
 *** Function Name : GPIO_ReadPins
 *** Description   : Reads input pins for a given port
 ******************************************************************************/
uint32_t GPIO_ReadPins(const GPIO_Type* regBase)
{
    return (GPIO_REG_ReadPins(regBase));
}

/*******EOF********************************************************************/
